# get_devices.py
import requests
import hashlib
import base64
import json
import urllib3
import datetime
import ipaddress
import os


urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class IKUAIAuth:
    def __init__(self, ADDR, USERNAME, PASSWORD, PORT=8443):
        self.ADDR = ADDR
        self.USERNAME = USERNAME
        self.PASSWORD = PASSWORD
        self.PORT = PORT
        self.base_url = f"https://{self.ADDR}:{self.PORT}"
        self.login_url = f"{self.base_url}/Action/login"
        self.call_url = f"{self.base_url}/Action/call"
        self.session = requests.Session()
        self.login()

    def _encode_password_md5(self):
        return hashlib.md5(self.PASSWORD.encode()).hexdigest()

    def _encode_pass_base64(self):
        raw = ("salt_11" + self.PASSWORD).encode("ASCII")
        return base64.b64encode(raw).decode()

    def login(self):
        payload = {
            "username": self.USERNAME,
            "passwd": self._encode_password_md5(),
            "pass": self._encode_pass_base64(),
            "remember_password": ""
        }
        headers = {
            "Content-Type": "application/json;charset=utf-8",
            "Accept": "application/json"
        }
        try:
            resp = self.session.post(self.login_url, data=json.dumps(payload), headers=headers, verify=False)
            resp.raise_for_status()
            result = resp.json()
            if result.get("Result") != 10000:
                raise Exception(f"登录失败: {result.get('ErrMsg')}")
        except Exception as e:
            raise e


class PayLoad(object):
    @staticmethod
    def payload(func_name, filter1, order, orderby, offset, limit):
        payload = {
            "func_name": func_name,
            "action": "show",
            "FINDS": "mac,ip_addr,comment",
            "param": {
                "TYPE": "data,total",
                "limit": f"{offset},{limit}",
                "ORDER": f"{order}",
                "ORDER_BY": f"{orderby}",
                "FILTER1": filter1,
            }
        }
        return payload


class GetDHCPDevices:
    def __init__(self, session, call_url, filter1, limit=100):
        self.FormatData = PayLoad
        self.session = session
        self.orderby = "ip_addr_int"
        self.limit = limit
        self.call_url = call_url
        self.func_name = "dhcp_lease"
        self.filter1 = filter1

    def ikuai_call(self):
        all_records = []
        offset = 0

        while True:
            payload = PayLoad.payload(func_name=self.func_name, filter1=self.filter1, orderby=self.orderby,
                                      offset=offset, limit=self.limit, order="desc")
            resp = self.session.post(self.call_url, data=json.dumps(payload), verify=False)
            resp.raise_for_status()

            data = resp.json().get("Data", {}).get("data", [])
            if not data:
                break

            all_records.extend(data)
            offset += self.limit
        return all_records


class FormatData(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        """迭代时只返回关心的字段"""
        exclude_net = ipaddress.ip_network("10.10.103.0/24")
        for item in self.data:
            ip_str = item.get("ip_addr", "")
            if ip_str and ipaddress.ip_address(ip_str) in exclude_net:
                continue  # 跳过这个 IP
            yield {
                "hostname": item.get("hostname", ""),
                "ip": item.get("ip_addr", ""),
                "mac": item.get("mac", ""),
                "start_time": datetime.datetime.fromtimestamp(
                    item.get("start_time", 0)
                ).strftime("%Y-%m-%d %H:%M:%S") if item.get("start_time") else ""
            }

    def format_table(self):
        """格式化为表格字符串"""
        rows = list(self)  # 调用 __iter__ 过滤好的数据
        if not rows:
            return "No data."

        # 表头映射：显示名 → 数据字段
        headers = [("Hostname", "hostname"),
                   ("IP Address", "ip"),
                   ("MAC Address", "mac"),
                   ("Start Time", "start_time")]

        # 计算每列最大宽度（取表头和内容的最大长度）
        col_widths = []
        for header, key in headers:
            max_len = max(len(str(row[key])) for row in rows)
            col_widths.append(max(max_len, len(header)))

        # 拼表头
        header_line = " | ".join(h.ljust(w) for (h, _), w in zip(headers, col_widths))
        separator = "-+-".join("-" * w for w in col_widths)

        # 拼内容
        lines = []
        for row in rows:
            line = " | ".join(
                str(row[key]).ljust(w)
                for (_, key), w in zip(headers, col_widths)
            )
            lines.append(line)

        return "\n".join([header_line, separator] + lines)


if __name__ == '__main__':
    # addr = os.getenv("addr")
    # username = os.getenv("username")
    # password = os.getenv("password")
    addr = "huize.hans.ltd"
    username = "admin"
    password = "Seven77@chan"

    auth = IKUAIAuth(addr, username, password)
    get_devices = GetDHCPDevices(auth.session, auth.call_url, filter1="interface,=,vlan_100")
    devices = get_devices.ikuai_call()
    info = FormatData(devices)
    print(info.format_table())
